package es.uned.etsii.si3.taller.misc;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.Period;

/**
 * 
 * Clase que proporciona un iterador inverso de semanas/meses, partiendo de un
 * día "semilla" que se incluya en el primer intervalo.
 * 
 * @author Ricardo Cárdenes
 *
 */
public class IteradorTemporalInverso implements Iterable<Interval> {
    private final DateTime inicio;
    private final DateTime fin;
    private Period periodo;

    /**
     * 
     * Inicializa el iterador usando un DateTime como "semilla" y el número de
     * periodos a contar. La semilla es un día cualquiera contenido en la semana
     * o mes inicial.
     * 
     * @param semilla         DateTime usado como referencia inicial
     * @param periodos        número de períodos a iterar
     * @param periodoSemanal  Se iteran semanas si es @true, meses si es @false
     */
    public IteradorTemporalInverso(DateTime semilla, int periodos, boolean periodoSemanal) {
            Period periodoTotal = null;

            if (periodoSemanal) {
                    inicio = new DateTime(semilla.getYear(), semilla.getMonthOfYear(), semilla.getDayOfMonth(), 0, 0, 0)
                                         .minusDays(semilla.dayOfWeek().get() - 1);
                    periodoTotal = new Period().withWeeks(periodos);
                    periodo = new Period().withWeeks(1);
            }
            else {
                    inicio = new DateTime(semilla.getYear(), semilla.getMonthOfYear(), 1, 0, 0, 0);
                    periodoTotal = new Period().withMonths(periodos);
                    periodo = new Period().withMonths(1);
            }

            fin = inicio.minus(periodoTotal);
    }

    public Iterator<Interval> iterator() {
            return new IteradorTemporalImplementacion(inicio, fin, periodo);
    }
    
    private class IteradorTemporalImplementacion implements Iterator<Interval> {
        private Period periodo;
        private Interval actual;
        private DateTime fin;

        public IteradorTemporalImplementacion(DateTime inicio, DateTime fin, Period periodo) {
                this.periodo = periodo;
                this.fin = fin;

                actual = new Interval(inicio, periodo);
        }

        public boolean hasNext() {
                return (actual != null);
        }

        public Interval next() {
                if (actual == null) {
                        throw new NoSuchElementException();
                }

                Interval ret = actual;

                if (actual.contains(fin.getMillis()))
                        actual = null;
                else
                        actual = new Interval( actual.getStart().minus(periodo), periodo );

                return ret;
        }

        public void remove() {
                throw new UnsupportedOperationException();
        }
    }
}
